package com.pangu.tracker;

import com.pangu.AMApplication;
import com.pangu.task.IResultReceiver;
import com.pangu.task.OperateResult;
import com.pangu.task.mark.ATaskMark;

import android.app.Activity;
import android.os.SystemClock;

import java.lang.ref.WeakReference;

/**
 * 调用的回调器，用于接收成功或失败的信息。 2010-6-16<br>
 * 它的作用范围是数据层, 只对存在的数据进行 保持或者处理。<br>
 * 作用域内存并于视图层建立连接，与服务链顶层MemoryService互补。<br>
 * 必要是可以执行固有的任务链处理。@see handleInvokeFinalize();
 * <p/>
 * Created by cxlin
 */
public abstract class AInvokeTracker {

    protected AMApplication imContext;

    // 结果跟踪，用于解释成功或失败的结果。
    // 安全考虑：弱应用
    private WeakReference<IResultReceiver> iReference;

    // 跟踪后的一个结果，用于处理某些临时的，瞬态的数据，以便将他们传递个视图成。
    protected Object trackerResult;

    public AInvokeTracker(AMApplication imContext, IResultReceiver resultReceiver) {
        this.imContext = imContext;
        this.iReference = new WeakReference<IResultReceiver>(resultReceiver);
    }

    public IResultReceiver getResultReceiver() {
        return iReference.get();
    }

    public void setResultReceiver(IResultReceiver iReference) {
        this.iReference = new WeakReference<IResultReceiver>(iReference);
    }

    /**
     * 预处理,在任务对应的方法执行完毕从后台执行方法退出前调用。 <br>
     * 默认执行等待依赖的任务。<br>
     * 注意：它不是在ui线程执行的。
     *
     * @param taskMark
     */
    public void handleInvoikePrepare(ATaskMark taskMark) {
        ATaskMark dependTask = taskMark.getDependTask();
        // 是否需要等待, 如果需要最多等待15s。注意只等待处理中的任务。
        if (dependTask != null && dependTask.getTaskStatus() == ATaskMark.HANDLE_DOING) {
            int tryCount = 0;
            while (true) {
                if (dependTask.getTaskStatus() != ATaskMark.HANDLE_DOING || tryCount >= 50) {
                    break;
                }
                SystemClock.sleep(150);
                tryCount++;
            }
        } else {
        }
    }

    /**
     * 任务的最终调用。注意:在ui线程调用，此时数据处理应该已经完成，如果没有错误的话。<br>
     * 默认执行取消依赖的任务。
     *
     * @param operateResult 本次任务可能的结果
     * @param taskMark
     */
    public void handleInvokeFinalize(OperateResult operateResult, ATaskMark taskMark) {

    }

    /**
     * 当任务执行完毕的时候的回调接口 注意，这个方法将在事件线程中调用。<br>
     * 注意:在ui线程调用。
     *
     * @param result
     */
    public void handleInvokeOver(OperateResult result) {
        // 传给接受者
        ATaskMark taskMark = result.getTaskMark();

        // 如果内部抛出未捕获的异常则提示错误
        try {
            if (taskMark.getTaskStatus() == ATaskMark.HANDLE_OVER) {
                // 实际的数据处理
                if (taskMark.getTaskType() == ATaskMark.TYPE_REFRESH) {
                    handleTaskRefresh(taskMark, result);
                }

                taskMark.setLastExecuteTime(System.currentTimeMillis());
                handleResult(result);

            } else {
                handleFault(result);
            }

        } catch (Exception e) {
            taskMark.setTaskStatus(ATaskMark.HANDLE_ERROR);
            e.printStackTrace();
        }

        // 传给接受者
        IResultReceiver receiver = getResultReceiver();
        if (receiver == null || (receiver instanceof Activity && ((Activity) receiver).isFinishing())) {

        } else {

            receiver.receiveResult(taskMark, result.getActionException(), trackerResult);
        }

        // 最后处理
        overHandleInvokeResult(result);
    }

    /**
     * 对方法结果最后处理
     *
     * @param result
     */
    protected abstract void overHandleInvokeResult(OperateResult result);

    /**
     * 日志标记
     *
     * @return
     */
    public abstract String TAG();

    /**
     * 当任务执行完毕的时候的回调接口 注意，这个方法将在事件线程中调用。<br>
     * 实际的数据处理延时达到子类完成。<br>
     * 这个方法只有在ATaskMark.HANDLE_OVER的时候才会调用，子类可以更具实际的<br>
     * 返回值合理的设置ATaskMark的状态。<br>
     * 注意:在ui线程调用。
     *
     * @param result
     */
    public abstract void handleResult(OperateResult result);

    /**
     * 子类重写处理刷新任务缓存
     *
     * @param taskMark
     * @param result
     */
    protected void handleTaskRefresh(ATaskMark taskMark, OperateResult result) {

    }

    /**
     * 如果是失败了，那么可能需要对数据进行一定的处理。<br>
     * 注意:在ui线程调用。
     */
    public void handleFault(OperateResult result) {

    }

    public Object getTrackerResult() {
        return trackerResult;
    }
}
